import requests
import pandas as pd
import json
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report
import time
import asyncio
import aiohttp
from typing import List, Dict


async def predict_intent_async(session, prompt: str) -> str:
    """
    异步调用预测API获取意图识别结果
    """
    try:
        async with session.post(
            "http://127.0.0.1:8800/predict",
            json={"prompt": prompt},
            timeout=aiohttp.ClientTimeout(total=30)
        ) as response:
            result = await response.json()
            return result.get("output", "")
    except Exception as e:
        print(f"预测出错: {e}")
        return ""

async def process_item_async(session, prompt: str) -> str:
    """
    异步处理单条数据
    """
    return await predict_intent_async(session, prompt)

async def batch_predict_async(prompts: List[str], max_workers: int = 10) -> List[str]:
    """
    异步批量预测
    """
    connector = aiohttp.TCPConnector(limit=max_workers)
    timeout = aiohttp.ClientTimeout(total=30)
    
    async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
        tasks = [process_item_async(session, prompt) for prompt in prompts]
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 处理异常结果
        processed_results = []
        for result in results:
            if isinstance(result, Exception):
                print(f"处理过程中发生错误: {result}")
                processed_results.append("")
            else:
                processed_results.append(result)
        
        return processed_results

def predict_intent(prompt: str) -> str:
    """
    调用预测API获取意图识别结果（同步版本，用于兼容旧代码）
    """
    try:
        response = requests.post(
            "http://127.0.0.1:8800/predict",
            json={"prompt": prompt},
            timeout=30
        )
        response.raise_for_status()
        result = response.json()
        return result.get("output", "")
    except Exception as e:
        print(f"预测出错: {e}")
        return ""


def main():
    # 读取CSV文件
    file_path = "/Users/sd/Desktop/mycode/myalgo/milvus/data-gen/zero_gen/intention.csv"
    df = pd.read_csv(file_path)
    
    print(f"总共读取到 {len(df)} 条数据")
    
    # 异步批量预测
    print("开始异步批量预测...")
    start_time = time.time()
    
    # 分批处理以避免连接数过多
    batch_size = 50
    predictions = []
    
    for i in range(0, len(df), batch_size):
        batch_prompts = df['prompt'][i:i+batch_size].tolist()
        print(f"正在处理第 {i+1}-{min(i+batch_size, len(df))} 条数据")
        
        # 运行异步批量预测
        batch_predictions = asyncio.run(batch_predict_async(batch_prompts, max_workers=10))
        predictions.extend(batch_predictions)
        
        # 添加延迟避免请求过于频繁
        time.sleep(0.1)
    
    end_time = time.time()
    print(f"预测完成，耗时: {end_time - start_time:.2f} 秒")
    
    # 将预测结果添加到DataFrame
    df['predict'] = predictions
    
    # 保存结果到新的CSV文件
    output_path = "/Users/sd/Desktop/mycode/myalgo/milvus/data-gen/zero_gen/intention_with_predictions.csv"
    df.to_csv(output_path, index=False)
    print(f"预测结果已保存到: {output_path}")

    # 如果有真实标签列，则进行评估
    if 'answer' in df.columns:
        y_t = df['answer']
        y_p = df['predict']

        # 过滤掉两个都为空的样本
        mask = ~((y_t == "") & (y_p == ""))
        y_true_filtered = y_t[mask]
        y_pred_filtered = y_p[mask]

        print(f"\n=== 评估结果 ===")
        print(f"总样本数: {len(df)}")
        print(f"有效评估样本数: {len(y_true_filtered)}")
        print(f"真实标签为空的样本数: {len(y_t[y_t == ''])}")
        print(f"预测标签为空的样本数: {len(y_p[y_p == ''])}")

        if len(y_true_filtered) == 0:
            print("警告: 没有有效的样本用于评估")
            return {
                'accuracy': 0.0,
                'precision': 0.0,
                'recall': 0.0,
                'f1': 0.0,
                'sample_count': 0,
                'valid_sample_count': 0
            }

        # 计算准确率
        accuracy = accuracy_score(y_true_filtered, y_pred_filtered)
        print(f"准确率 (Accuracy): {accuracy:.4f}")

        # 计算精确率、召回率和F1分数（宏平均）
        try:
            precision = precision_score(y_true_filtered, y_pred_filtered, average='macro', zero_division=0)
            recall = recall_score(y_true_filtered, y_pred_filtered, average='macro', zero_division=0)
            f1 = f1_score(y_true_filtered, y_pred_filtered, average='macro', zero_division=0)

            print(f"精确率 (Precision, macro): {precision:.4f}")
            print(f"召回率 (Recall, macro): {recall:.4f}")
            print(f"F1分数 (F1-score, macro): {f1:.4f}")
        except Exception as e:
            print(f"计算Precision/Recall/F1时出错: {str(e)}")
            precision, recall, f1 = 0.0, 0.0, 0.0

        # 生成详细分类报告
        try:
            print(f"\n=== 详细分类报告 ===")
            report = classification_report(y_true_filtered, y_pred_filtered, zero_division=0)
            print(report)
        except Exception as e:
            print(f"生成分类报告时出错: {str(e)}")

        # 计算完全匹配率（严格匹配）
        exact_match = (y_true_filtered == y_pred_filtered).mean()
        print(f"完全匹配率: {exact_match:.4f}")

        result = {
            'accuracy': accuracy,
            'precision': precision,
            'recall': recall,
            'f1': f1,
            'exact_match': exact_match,
            'sample_count': len(df),
            'valid_sample_count': len(y_true_filtered)
        }

        print(result)
        return result
    else:
        print("数据中没有标签列，无法进行评估")


if __name__ == "__main__":
    main()